#include "../GenericTypeDefs.h"
#include "../src/CommandHandler.h"
#include "../src/Common.h"
#include "../src/Framework.h"
#include "../src/SPI_FrameWork.h"
#include "../src/PanelComm.h"
#include "../src/IoComm.h"
#include "../src/HT_update.h"
#include "config/pic32mk_mcm_curiosity_pro/peripheral/nvm/plib_nvm.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "Uart5.h"
#include "Uart1.h"
#include "../src/config/pic32mk_mcm_curiosity_pro/peripheral/spi/spi_master/plib_spi4_master.h"
#include "SPI.h"

extern void Timer1_Polled(void);
extern BOOL b1ms;

void HandlePanelCommCommand(void);
void HandleUpgradeStation(uint8_t cmd);
void HandleProgramLayerStation(uint8_t cmd);
bool HandleUpgradeStation_Uart(uint8_t cmd);
bool HandleUpgradeStation_RotateAxis(uint8_t cmd);
bool HandleUpgradeStation_ExtendAxis(uint8_t cmd);
bool HandleUpgradeStation_Transfer(uint8_t cmd);
void HandleWrongStation(void);
void CommandHandler_Execute(void);
void PopulateRplyPack(void);
void PopulateIoUartCmdPack(void);
void Panel_TxStationCmd_63(void);
extern BOOL CheckAppProgram(void);

void CommandHandler_Execute(void) 
{
    if (PanelComm_ChkAndClearPackValidFlag()) 
    {
        HandlePanelCommCommand();	
    }
}

bool IsTransferMode()
{
    uint8_t mode = GetMode();
    uint8_t slaveNum = GetSlaveNum();
    return mode == PROGRAM_MODE && slaveNum > 1;
}

void HandlePanelCommCommand(void) 
{
    bool isToReply = true;

    uint8_t stationNum = PanelCommRecPacket.StationNum;   
    switch (stationNum) 
    {
        case 0xE0:
            if (!IsTransferMode() || PanelCommRecPacket.Cmd == SET_MODE) //0x05
            {
                HandleUpgradeStation(PanelCommRecPacket.Cmd);
            } 
            else
            {
                if (GetSlaveNum() == 9) // IO
                {
                    isToReply = HandleUpgradeStation_Uart(PanelCommRecPacket.Cmd);
                }
                else if(GetSlaveNum() == 7) // Rotation Axis    //TODO:This plan does not include Rotation Axis.
                {
                    isToReply = HandleUpgradeStation_RotateAxis(PanelCommRecPacket.Cmd);
                }
                else if(GetSlaveNum() == 11) // Extend Axis
                {
                    isToReply = HandleUpgradeStation_ExtendAxis(PanelCommRecPacket.Cmd);
                }        
                else 
                {
                    isToReply = HandleUpgradeStation_Transfer(PanelCommRecPacket.Cmd);
                }
            }
            break;
            
        case 0xE1:
            HandleProgramLayerStation(PanelCommRecPacket.Cmd);
            break;
            
        case 0x63:
            Panel_TxStationCmd_63();
            break;
            
        default:
            HandleWrongStation();
            break;
    }

    if (isToReply)
    {
        PanelComm_FillTxBytesWithRplyPack();
    }
}

void HandleWrongStation(void)
{
    PanelCommRplyPacket.PackIndex = PanelCommRecPacket.PackIndex;
    PanelCommRplyPacket.StationNum = PanelCommRecPacket.StationNum;
    PanelCommRplyPacket.Cmd = 0xFF;
    PanelCommRplyPacket.Data[0] = 0x01;
    PanelCommRplyPacket.DataByteLength = 1;
    PanelCommRplyPacket.PackLength = PanelCommRplyPacket.DataByteLength + 7;
    PanelCommRplyPacket.PackHead = 0xAA;
    PanelCommRplyPacket.PackTail = 0xBB;
}

void HandleProgramLayerStation(uint8_t cmd) {
    switch (cmd) {
        case READ_PROGRAM_LAYER:
            PanelCommRplyPacket.Cmd = READ_PROGRAM_LAYER_BACK;
            PanelCommRplyPacket.DataByteLength = 2;
            PanelCommRplyPacket.Data[0] = 0x01;
            PanelCommRplyPacket.Data[1] = 0x00;
            break;
        case 0x03:
            CheckAppProgram();
            break;
        default:
            PanelCommRplyPacket.Cmd = 0xF0;
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Data[0] = 2;//no such command
            break;
    }

    PopulateRplyPack();
}

void HandleUpgradeStation(uint8_t cmd) {
    static bool spiInited = false;

    switch (cmd)
    {
        case READ_VER_INFO: // 0x04
        {
            PanelCommRplyPacket.Cmd = READ_VER_INFO_BACK;   // 0xF4
            const char* verStr = MAIN_BOOT_VER;
            uint8_t verStrLen = strlen(verStr);
            PanelCommRplyPacket.DataByteLength = verStrLen;
            int i;
            for (i = 0; i < verStrLen; i++) 
            {
                PanelCommRplyPacket.Data[i] = verStr[i];
            }
            break;
        }

        case SET_MODE: // 0x05
        {
            BootMode mode = PanelCommRecPacket.Data[0];     // 0x00
            uint8_t slaveNum = PanelCommRecPacket.Data[1];  // 0x01
            
            if (mode == PROGRAM_MODE)   //0x01
            {
                SetModeSlave(PROGRAM_MODE, slaveNum);
            } 
            else 
            {
                SetModeSlave(NORMAL_MODE, 0);
            }

            if (mode == PROGRAM_MODE && slaveNum > 1 && slaveNum < 9)   // Holtek
            {
                if (!spiInited) 
                {
//                  SPI_Initialize();
                    spiInited = true;
                }

                int i;
                for (i = 0; i < 10; i++)
                {
                    QIXIN_EnterBoot(slaveNum);
                    int j,k;
                    for(j = 0; j < 200; j++)
                    {
                        // Cheap delay. This should give at leat 1 ms delay.
                        for (k = 0; k < 2000; k++)
                        {
                            asm("nop");
                        }
                    }
                }
                if(7 == slaveNum)   // Rotation Axis    //TODO:This plan does not include Rotation Axis.
                {
//                    SPI4_ReInitialize();
//                    SPI4_CallbackRegister(SPIEventHandler, (uintptr_t) 0); 
                } 
                int j;
                for (j = 0; j < 10000; j++)
                {
                    Nop();Nop();
                }            
            }
            else if (mode == PROGRAM_MODE && slaveNum == 9)     // IO
            {
                IoCommEnterBoot();
            }
            else if (mode == PROGRAM_MODE && slaveNum == 11)    //Extend Axis
            {
                ExtendAxisEnterBoot();
            }
            PanelCommRplyPacket.Cmd = SET_MODE_BACK;        // 0xF5
            PanelCommRplyPacket.Data[0] = 0;
            PanelCommRplyPacket.DataByteLength = 1;
            break;
        }

        case ERASE_FLASH:   // 0x06
        {
            if (!IsEraseFlashEnabled())
            {
                PanelCommRplyPacket.Data[0] = 4;
            }
            else //erase master chip
            {
                if (NVM_PageErase(USER_MSG_ADDRESS)) 
                {
                    while(NVMCONbits.WR);
                    uint32_t Er_Add;
                    for (Er_Add = USER_ERASE_ADDRESS; Er_Add < USER_APP_END_ADDRESS; (Er_Add = Er_Add + NVM_FLASH_PAGESIZE))
                    {
                        if(!NVM_PageErase(Er_Add))
                        {
                            PanelCommRplyPacket.Data[0] = 2;
                            break;
                        }
                        while(NVMCONbits.WR);
                    }
                    SetProgramFlashEnabled(true);
                    PanelCommRplyPacket.Data[0] = 0;
                } 
                else 
                {
                    PanelCommRplyPacket.Data[0] = 2;
                }
            } 
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Cmd = ERASE_FLASH_BACK; // 0xF6
            break;
        }

        case PROGRAM_FLASH:     // 0x07
        {
            if (!IsProgramFlashEnabled())
            {
                PanelCommRplyPacket.Data[0] = 4;
            }
            else
            {              
                uint8_t hexRecordLen = PanelCommRecPacket.DataByteLength;
                UINT result = WriteHexRecord2Flash(PanelCommRecPacket.Data, hexRecordLen);
                if (result == 0)
                {
                    PanelCommRplyPacket.Data[0] = 0;
                }
                else
                {
                    PanelCommRplyPacket.Data[0] = (uint8_t)result;
                }
            }
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Cmd = PROGRAM_FLASH_BACK;   // 0xF7
            break;
        }

        case CHECK_CRC: 
        {
            SetProgramFlashEnabled(FALSE);
            SetEraseFlashEnabled(FALSE);

            WORD_VAL crc;
            crc.v[0] = PanelCommRecPacket.Data[0];
            crc.v[1] = PanelCommRecPacket.Data[1];  // It should be low first
            
            if (GetCrcData() == crc.Val) 
            {
                if (NVM_WordWrite(DEF_APP_FLAY , APP_Flay_FlashAddr))     
                {
                    PanelCommRplyPacket.Data[0] = 0;
                } 
                else 
                {
                    PanelCommRplyPacket.Data[0] = 2;
                }
            }
            else
            {
                PanelCommRplyPacket.Data[0] = 1;
            }
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Cmd = CHECK_CRC_BACK;
            break;
        }

        default:
            PanelCommRplyPacket.Cmd = 0xF0;
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Data[0] = 2;    // no such command
            break;
    }
    PopulateRplyPack();
}

bool HandleUpgradeStation_ExtendAxis(uint8_t cmd) {
    bool isToReply;
    switch (cmd) {
        case READ_VER_INFO: {   //0x04
			u1TxPkt.cmd = READ_VER_INFO;
            u1TxPkt.dataLen = PanelCommRecPacket.DataByteLength;
            
            uint8_t i =0;
			for(i = 0; i < u1TxPkt.dataLen; i++) {
				u1TxPkt.dataBuf[i] = PanelCommRecPacket.Data[i];
			}
			BuildTxPktToExtendAxis();
            ExtendAxis_FillTxBytesWithRplyPack();
            isToReply = false;
            break;
        }

        case SET_MODE: {   //0x05
            return false;
        }

        case ERASE_FLASH: {     //0x06
            u1TxPkt.cmd = ERASE_FLASH;
            u1TxPkt.dataLen = PanelCommRecPacket.DataByteLength;
            
            uint8_t i =0;
			for(i = 0; i < u1TxPkt.dataLen; i++) {
				u1TxPkt.dataBuf[i] = PanelCommRecPacket.Data[i];
			}
            BuildTxPktToExtendAxis();
            ExtendAxis_FillTxBytesWithRplyPack();
            isToReply = false;
            break;
        }
       
        case PROGRAM_FLASH: {   //0x07
            u1TxPkt.cmd = PROGRAM_FLASH;
            u1TxPkt.dataLen = PanelCommRecPacket.DataByteLength;
            
            uint8_t i =0;
			for(i = 0; i < u1TxPkt.dataLen; i++) {
				u1TxPkt.dataBuf[i] = PanelCommRecPacket.Data[i];
			}
            BuildTxPktToExtendAxis();
            ExtendAxis_FillTxBytesWithRplyPack();
            isToReply = false;
            break;
        }

        case CHECK_CRC: {   //0x08
            u1TxPkt.cmd = CHECK_CRC;
            u1TxPkt.dataLen = PanelCommRecPacket.DataByteLength;
            
            uint8_t i =0;
			for(i = 0; i < u1TxPkt.dataLen; i++) {
				u1TxPkt.dataBuf[i] = PanelCommRecPacket.Data[i];
			}
            BuildTxPktToExtendAxis();
            ExtendAxis_FillTxBytesWithRplyPack();
            isToReply = false;
            break;
        }

        default:
            PanelCommRplyPacket.Cmd = 0xF0;
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Data[0] = 2;    //no such command

            PopulateRplyPack();
            return true;
    }
    return isToReply;
}

bool HandleUpgradeStation_RotateAxis(uint8_t cmd) {
    uint8_t SetSendLen = PanelCommRecPacket.PackLength + 2;
    if((PanelCommRecPacket.PackLength + 2) % 4 != 0)
    {
        SetSendLen = PanelCommRecPacket.PackLength + 2 + 4 - (PanelCommRecPacket.PackLength + 2) % 4;
    }
    switch (cmd)
    {
        case READ_VER_INFO: //0x04
        {
            RotateAxis_FillTxBytesWithRplyPack();
            SlaveSelect(7);
            delay(10);
            SPI4_WriteRead(PanelTxData_CK,SetSendLen,NULL,0);
            delay(10);
            
            const char* verStr = MAIN_BOOT_VER;
            uint8_t verStrLen = strlen(verStr);
            PanelCommRplyPacket.DataByteLength = verStrLen;
            PanelCommRplyPacket.Cmd = READ_VER_INFO_BACK;   //0xF4
            int i;
            for (i = 0; i < verStrLen; i++) 
            {
                PanelCommRplyPacket.Data[i] = verStr[i];
            }
            PopulateRplyPack();           
            return true;
        }

        case SET_MODE:  //0x05
        {
            return false;
        }

        case ERASE_FLASH:   //0x06
        {
            RotateAxis_FillTxBytesWithRplyPack();
            SlaveSelect(7);
            delay(10);
            SPI4_WriteRead(PanelTxData_CK,SetSendLen,NULL,0);
            delay(10);

            SPI_WorkMsg.Read_En_ck = 1;         
            SPI_WorkMsg.Cmd = ERASE_FLASH_SPI;  //0x43    
            TMR1 = 0x0000;   
            SPI_WorkMsg.DlayValue = DELAY_2000MS_VALUE;     // delay 2 S
            return false; 
        }
       
        case PROGRAM_FLASH:     //0x07
        {
            RotateAxis_FillTxBytesWithRplyPack();
            SlaveSelect(7);
            delay(10);
            SPI4_WriteRead(PanelTxData_CK,SetSendLen,NULL,0);
            delay(10);
            
            SPI_WorkMsg.Read_En_ck = 1;  
            SPI_WorkMsg.Cmd = PROGRAM_FLASH_SPI;    //0x44        
            TMR1 = 0x0000;   
            SPI_WorkMsg.DlayValue = DELAY_3MS_VALUE;   
            return false; 
        }

        case CHECK_CRC:     //0x08
        {
            RotateAxis_FillTxBytesWithRplyPack();
            SlaveSelect(7);
            delay(10);
            SPI4_WriteRead(PanelTxData_CK,SetSendLen,NULL,0);
            delay(10);
            
            SPI_WorkMsg.Read_En_ck = 1;
            SPI_WorkMsg.Cmd = CHECK_CRC_SPI;    //0x45
            TMR1 = 0x0000;
            SPI_WorkMsg.DlayValue = DELAY_200MS_VALUE;   
            return false;   
        }

        default:
            PanelCommRplyPacket.Cmd = 0xF0;
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Data[0] = 2;    //no such command
            PopulateRplyPack();
            return true;
    }
}

bool HandleUpgradeStation_Transfer(uint8_t cmd) {
    switch (cmd)
    {
        case READ_VER_INFO:     //0x04
        {
            New_SPI_MSG.WData[0] = READ_VER_INFO_SPI;   //0xC1
            New_SPI_MSG.WData[1] = 4;       // len
            New_SPI_MSG.WData[2] = 0;       // data0 ~ data3
            New_SPI_MSG.WData[3] = 0;
            New_SPI_MSG.WData[4] = 0;
            New_SPI_MSG.WData[5] = 0;
            New_SPI_MSG.Len = 6;              // Cmd + len + data (4 byte)=6 
            uint8_t state = SPI_ReadInstruction(GetSlaveNum(), &New_SPI_MSG);

            PanelCommRplyPacket.Cmd = READ_VER_INFO_BACK;   //0xF4
            char strBuf[21];
            int strLen;
            if (state == 0)
            {
                strLen = snprintf(strBuf, 21, BOOT_VER_FORMAT, GetSlaveNum(), New_SPI_MSG.RData[0], New_SPI_MSG.RData[1], New_SPI_MSG.RData[2], New_SPI_MSG.RData[3]);
            }
            else
            {
                strLen = snprintf(strBuf, 21, BOOT_VER_FORMAT, GetSlaveNum(), 0, 0, 0, 0);
            }
            PanelCommRplyPacket.DataByteLength = strLen;
            int i;
            for (i = 0; i < strLen; i++)
            {
                PanelCommRplyPacket.Data[i] = strBuf[i];
            }
            PopulateRplyPack();
            return true;
        }

        case SET_MODE:  //0x05
        {
            return false;
        }

        case ERASE_FLASH:   //0x06
        {
            New_SPI_MSG.WData[0] = ERASE_FLASH_SPI; //0x43        
            New_SPI_MSG.WData[1] = 0;          // len
            New_SPI_MSG.Len = 2;                 // Cmd + len
            SPI_WriteInstruction(GetSlaveNum(), &New_SPI_MSG);        
                
            SPI_WorkMsg.Read_En = 1;         
            SPI_WorkMsg.Cmd = ERASE_FLASH_SPI;  //0x43         
            SPI_WorkMsg.DlayValue = DELAY_2000MS_VALUE; // delay 2 S

            return false;
        }
       
        case PROGRAM_FLASH: //0x07
        {
            uint8_t dataLen = PanelCommRecPacket.DataByteLength;

            if (dataLen > 0 && dataLen <= 64)
            {
                New_SPI_MSG.WData[0] = PROGRAM_FLASH_SPI;   //0x44
                New_SPI_MSG.WData[1] = dataLen;
                int i;
                for (i = 0; i < dataLen; i++)
                {
                    New_SPI_MSG.WData[2 + i] = PanelCommRecPacket.Data[i];  
                }
                New_SPI_MSG.Len = 2 + dataLen;                          // Cmd + len + data
                SPI_WriteInstruction(GetSlaveNum(), &New_SPI_MSG);   
                    
                SPI_WorkMsg.Read_En = 1;  
                SPI_WorkMsg.Cmd = PROGRAM_FLASH_SPI;    //0x44        
                TMR1 = 0x0000;   
                SPI_WorkMsg.DlayValue = DELAY_3MS_VALUE;      
            }
            else
            {
                //shouldn't happen
            }
            return false;
        }

        case CHECK_CRC:     //0x08
        {
            New_SPI_MSG.WData[0] = CHECK_CRC_SPI;   //0x45
            New_SPI_MSG.WData[1] = 2;                 // len
            New_SPI_MSG.WData[2] = PanelCommRecPacket.Data[0];  
            New_SPI_MSG.WData[3] = PanelCommRecPacket.Data[1];
            New_SPI_MSG.Len = 4;
            SPI_WriteInstruction(GetSlaveNum(), &New_SPI_MSG);  
                
            SPI_WorkMsg.Read_En = 1;
            SPI_WorkMsg.Cmd = CHECK_CRC_SPI;    //0x45
            TMR1 = 0x0000;
            SPI_WorkMsg.DlayValue = DELAY_200MS_VALUE;   

            return false;
        }

        default:
            PanelCommRplyPacket.Cmd = 0xF0;
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Data[0] = 2;    //no such command

            PopulateRplyPack();
            return true;
    }
}

bool HandleUpgradeStation_Uart(uint8_t cmd) {
    bool isToReply;

    switch (cmd)
    {
        case READ_VER_INFO: //0x04
        {
            IoCommCmdPacket.Members.Cmd = READ_VER_INFO_SPI;    //0xC1
            IoCommCmdPacket.Members.DataByteLength = 4;
            IoCommCmdPacket.Members.Data[0] = 0;
            IoCommCmdPacket.Members.Data[1] = 0;
            IoCommCmdPacket.Members.Data[2] = 0;
            IoCommCmdPacket.Members.Data[3] = 0;
            PopulateIoUartCmdPack();
            isToReply = false;
            break;
        }

        case SET_MODE:  //0x05
        {
            return false;
        }

        case ERASE_FLASH:   //0x06
        {
            IoCommCmdPacket.Members.Cmd = ERASE_FLASH_SPI;  //0x43
            IoCommCmdPacket.Members.DataByteLength = 0;
            PopulateIoUartCmdPack();
            isToReply = false;
            break;
        }
       
        case PROGRAM_FLASH: //0x07
        {
            uint8_t dataLen = PanelCommRecPacket.DataByteLength;

            IoCommCmdPacket.Members.Cmd = PROGRAM_FLASH_SPI;    //0x44
            IoCommCmdPacket.Members.DataByteLength = dataLen;
            int i;
            for (i = 0; i < dataLen; i++)
            {
                IoCommCmdPacket.Members.Data[i] = PanelCommRecPacket.Data[i];
            }

            PopulateIoUartCmdPack();
            isToReply = false;
            break;
        }

        case CHECK_CRC: //0x08
        {
           uint8_t dataLen = PanelCommRecPacket.DataByteLength;

            IoCommCmdPacket.Members.Cmd = CHECK_CRC_SPI;    //0x45
            IoCommCmdPacket.Members.DataByteLength = dataLen;
            int i;
            for (i = 0; i < dataLen; i++)
            {
                IoCommCmdPacket.Members.Data[i] = PanelCommRecPacket.Data[i];
            }

            PopulateIoUartCmdPack();
            isToReply = false;
            break;
        }

        default:
            PanelCommRplyPacket.Cmd = 0xF0;
            PanelCommRplyPacket.DataByteLength = 1;
            PanelCommRplyPacket.Data[0] = 2;    //no such command

            PopulateRplyPack();
            return true;
    }

    IoComm_FillTxBytesWithCmdPack();
    return isToReply;
}

void Panel_TxStationCmd_63(void) {
    const char *MainVer = "01:00.00.00";
    const char *XVer    = "02:00.00.00";  
    const char *YVer    = "03:00.00.00";  
    const char *ZVer    = "04:00.00.00"; 
    const char *IVVer   = "05:00.00.00"; 
    const char *VVer    = "06:00.00.00";  
    const char *VIVer   = "07:X0100_M22_00_00_00";
    const char *VIIVer  = "08:00.00.00"; 
    const char *GpioVer = "09:00.00.00";
    const char *CommVer = "10:00.00.00_V00";
    uint8_t MainLen,XLen,YLen,ZLen,IVLen,VLen,VILen,VIILen,GpioLen,CommLen;
    uint8_t Start,i;

    if(PanelCommRecPacket.Cmd == 0x02) {
        //master
        Start = 0;
        MainLen = strlen(MainVer);
        for(i = 0; i < MainLen; i++) {
            PanelCommRplyPacket.Data[i] = *(MainVer + i);
        }
        PanelCommRplyPacket.Data[MainLen] = ',';

        //X
        Start = Start + MainLen + 1;
        XLen = strlen(XVer);
        for(i = 0; i < XLen; i++) {
            PanelCommRplyPacket.Data[Start + i] = *(XVer+i);
        }
        PanelCommRplyPacket.Data[Start + XLen ] = ',';

        //Y
        Start = Start + XLen + 1;
        YLen = strlen(YVer);
        for(i = 0; i < YLen; i++) {
            PanelCommRplyPacket.Data[Start + i] = *(YVer+i);
        }
        PanelCommRplyPacket.Data[Start + YLen] = ',';

        //Z
        Start = Start + YLen + 1;
        ZLen = strlen(ZVer);
        for(i = 0; i < ZLen; i++) {
            PanelCommRplyPacket.Data[Start + i] = *(ZVer+i);
        }
        PanelCommRplyPacket.Data[Start + ZLen] = ',';

        //IV
        Start = Start + ZLen + 1;
        IVLen = strlen(IVVer);
        for(i = 0; i < IVLen; i++) {
            PanelCommRplyPacket.Data[Start + i] = *(IVVer+i);
        }
        PanelCommRplyPacket.Data[Start + IVLen] = ',';

        //V
        Start = Start + IVLen + 1;
        VLen = strlen(VVer);
        for(i = 0; i < VLen; i++) {
            PanelCommRplyPacket.Data[Start + i] = *(VVer+i);
        }
        PanelCommRplyPacket.Data[Start + VLen] = ',';

        //VI
        Start = Start + VLen + 1;
        VILen = strlen(VIVer);
        for(i = 0; i < VILen; i++) {
            PanelCommRplyPacket.Data[Start + i] = *(VIVer+i);
        }
        PanelCommRplyPacket.Data[Start + VILen] = ',';

        //VII�
        Start = Start + VILen + 1;
        VIILen = strlen(VIIVer);
        for(i = 0; i < VIILen; i++) {
            PanelCommRplyPacket.Data[Start + i] = *(VIIVer+i);
        }
        PanelCommRplyPacket.Data[Start + VIILen] = ',';

        //GPIO
        Start = Start + VIILen + 1;
        GpioLen = strlen(GpioVer);
        for(i = 0; i < GpioLen; i++) {                
            PanelCommRplyPacket.Data[Start + i] = *(GpioVer+i);
        }
        PanelCommRplyPacket.Data[Start + GpioLen] = ',';

        //RS232
        Start =Start + GpioLen + 1;
        CommLen = strlen(CommVer);
        for(i = 0; i < CommLen; i++) {
            PanelCommRplyPacket.Data[Start + i] = *(CommVer+i);
        }
        PanelCommRplyPacket.DataByteLength = MainLen + XLen + YLen + ZLen + IVLen + VLen + VILen + VIILen + GpioLen + CommLen + 9;
        PanelCommRplyPacket.Cmd = 0xF2;
    } else {
        PanelCommRplyPacket.Cmd = 0xF0;
        PanelCommRplyPacket.Data[0] = 0x02;
        PanelCommRplyPacket.DataByteLength = 1;
    }
    PopulateRplyPack();  
}

void PopulateRplyPack(void)
{
    PanelCommRplyPacket.PackIndex = PanelCommRecPacket.PackIndex;
    PanelCommRplyPacket.StationNum = PanelCommRecPacket.StationNum;
    PanelCommRplyPacket.PackLength = PanelCommRplyPacket.DataByteLength + 7;
    PanelCommRplyPacket.PackHead = 0xAA;
    PanelCommRplyPacket.PackTail = 0xBB;
}

void PopulateIoUartCmdPack(void)
{
    IoCommCmdPacket.Members.PackHead = 0xAA;
    IoCommCmdPacket.Members.Crc = Crc_Fun(&IoCommCmdPacket.Members.Cmd, IoCommCmdPacket.Members.DataByteLength + 2, 0);
}